using System;
using System.Collections.Generic;
using System.IO;

namespace PeDALS.Tools.AZ.PSTArchive.PSTData
{
    internal class PSTBTH
    {
        private byte mbType;
        private byte mbKeySize;
        private byte mbEntrySize;
        private byte mbIndexDepth;
        private UInt32 m32HIDrawRoot;
        List<PSTBTHLeaf> mlpblBTHLeaves;

        internal PSTBTH(UInt32 u32HIDraw, SortedList<UInt32, byte[]> slbaBlock)
        {
            MemoryStream msBTH = new MemoryStream(slbaBlock[u32HIDraw]);
            BinaryReader brBTHReader = new BinaryReader(msBTH);
            mbType = brBTHReader.ReadByte();
            mbKeySize = brBTHReader.ReadByte();
            mbEntrySize = brBTHReader.ReadByte();
            mbIndexDepth = brBTHReader.ReadByte();
            m32HIDrawRoot = brBTHReader.ReadUInt32();
            mlpblBTHLeaves = LoadBTHLeaves(m32HIDrawRoot, mbIndexDepth, slbaBlock);
            if (msBTH != null)
            {
                msBTH.Flush();
                msBTH.Close();
            }
            msBTH = null;
            if (brBTHReader != null)
            {
                brBTHReader.Close();
            }
            brBTHReader = null;
        }

        internal byte Type
        {
            get { return mbType; }
        }

        internal byte KeySize
        {
            get { return mbKeySize; }
        }

        internal byte EntrySize
        {
            get { return mbEntrySize; }
        }

        internal byte IndexDepth
        {
            get { return mbIndexDepth; }
        }

        internal UInt32 HIDrawRoot
        {
            get { return m32HIDrawRoot; }
        }

        internal UInt16 HID
        {
            get { return (UInt16)((m32HIDrawRoot >> 5) & 0x3ff); }
        }

        internal byte UserRootHIDType
        {
            get { return (byte)(m32HIDrawRoot & 0x1f); }
        }

        internal UInt16 HIDBlockIndex
        {
            get { return (UInt16)(m32HIDrawRoot >> 16); }
        }

        internal List<PSTBTHLeaf> BTHLeaves
        {
            get { return mlpblBTHLeaves; }
        }

        private List<PSTBTHLeaf> LoadBTHLeaves(UInt32 u32HIDraw, byte bIndexDepth, SortedList<UInt32, byte[]> slbaBlock)
        {
            List<PSTBTHLeaf> lpblBTHResults = new List<PSTBTHLeaf>();
            if (slbaBlock.ContainsKey(u32HIDraw))
            {
                MemoryStream msBTHLeaf = new MemoryStream(slbaBlock[u32HIDraw]);
                BinaryReader brBTHLeafReader = new BinaryReader(msBTHLeaf);
                if (bIndexDepth > 0)
                {
                    List<PSTBTHLeaf> lpblBTHHIDrawSub = new List<PSTBTHLeaf>();
                    do
                    {
                        lpblBTHHIDrawSub.Add(new PSTBTHLeaf(brBTHLeafReader.ReadBytes(mbKeySize), brBTHLeafReader.ReadUInt32()));
                    } while (brBTHLeafReader.BaseStream.Position < brBTHLeafReader.BaseStream.Length);
                    foreach (PSTBTHLeaf pblLeaf in lpblBTHHIDrawSub)
                    {
                        lpblBTHResults.AddRange(LoadBTHLeaves(pblLeaf.HIDraw, (byte)(bIndexDepth - 1), slbaBlock));
                    }
                }
                else
                {
                    do
                    {
                        lpblBTHResults.Add(new PSTBTHLeaf(brBTHLeafReader.ReadBytes(mbKeySize), brBTHLeafReader.ReadBytes(mbEntrySize)));
                    } while (brBTHLeafReader.BaseStream.Position < brBTHLeafReader.BaseStream.Length);
                }
                if (msBTHLeaf != null)
                {
                    msBTHLeaf.Flush();
                    msBTHLeaf.Close();
                }
                msBTHLeaf = null;
                if (brBTHLeafReader != null)
                {
                    brBTHLeafReader.Close();
                }
                brBTHLeafReader = null;
            }
            return lpblBTHResults;
        }
    }
}